package base.core.spring;

import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.compress.utils.Lists;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

import base.core.api.BaseFeign;
import base.core.api.Result;
import base.core.exception.BaseException;
import base.core.util.Beans;
import lombok.extern.slf4j.Slf4j;

/**
 * @Description
 * @Author Pengwei
 * @CreatDate 2021/12/16 15:56
 */
@Slf4j
public class BaseController<X extends BaseService, T> implements BaseFeign<T> {
    protected T typeBean;

    @Autowired
    protected X service;

    public LambdaQueryWrapper<T> getLambdaQuery() {
        return Wrappers.<T>lambdaQuery();
    }

    public LambdaQueryWrapper<T> getLambdaQuery(T t) {
        return Wrappers.<T>lambdaQuery(t);
    }

    @Override
    public Result<T> getOne(T condition) {
        return (Result<T>) Result.success(service.getOne(Wrappers.query(condition), false));
    }

    @Override
    public Result<List<T>> getList(T condition) {
        return Result.success(service.list(Wrappers.query(condition)));
    }

    @Override
    public Result<Page<T>> getPage(Long size, Long current, Boolean searchCount, String[] orders, T condition) {
        Page<T> page = new Page();
        if (size != null) page.setSize(size);
        if (current != null) page.setCurrent(current);
        if (searchCount != null) page.setSearchCount(searchCount);
        //排序字段
        List<OrderItem> orderItems = getOrderItems(orders);
        if (CollectionUtils.isNotEmpty(orderItems)) page.setOrders(orderItems);
        return Result.success((Page<T>) service.page(page, Wrappers.query(condition)));
    }

    public List<OrderItem> getOrderItems(String[] orders) {
        List<OrderItem> list = Lists.newArrayList();
        if (ArrayUtils.isEmpty(orders)) {
            return list;
        }
        for (String order : orders) {
            if (StringUtils.isBlank(order)) {
                continue;
            }
            String[] split = order.trim().split(" ");
            OrderItem orderItem = new OrderItem();
            orderItem.setColumn(split[0]);
            if (split.length == 2) {
                orderItem.setAsc(!"desc".equalsIgnoreCase(split[1]));
            }
            list.add(orderItem);
        }
        return list;
    }

    @Override
    public Result<T> getById(Serializable id) {
        return Result.success((T) service.getById(convertIdType(id)));
    }

    @Override
    public Result<T> create(T record) {
        return (Result<T>) Result.ofBol(service.save(record)).setData(record);
    }

    @Override
    public Result<T> update(T record) {
        return (Result<T>) Result.ofBol(service.updateById(record)).setData(record);
    }

    @Override
    public Result deleteById(Serializable id) {
        return Result.ofBol(service.removeById(convertIdType(id)));
    }

    @Override
    public Result<T> saveOrUpdate(T record) {
        return (Result<T>) Result.ofBol(service.saveOrUpdate(record)).setData(record);
    }

    @Override
    public Result saveOrUpdateBatch(Collection<T> records) {
        return Result.ofBol(service.saveOrUpdateBatch(records));
    }

    @Override
    public Result updateBatchById(List<T> records) {
        return Result.ofBol(service.updateBatchById(records));
    }

    @Override
    public Result updateBatch(T record, T condition) {
        return Result.ofBol(service.update(record, Wrappers.query(condition)));
    }

    @Override
    public Result ping() {
        return Result.success().setData("ok");
    }

    //转换ID的类型
    private Serializable convertIdType(Serializable id) {
        try {
            //获取泛型
            Class tClass = (Class) ((java.lang.reflect.ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[1];
            Field idField = Arrays.stream(tClass.getDeclaredFields()).filter(field -> field.getAnnotation(TableId.class) != null).findAny().orElse(null);
            return (Serializable) Beans.asObj(id, idField.getType());
        } catch (Exception e) {
           throw BaseException.of("id 转换失败",e);
        }
    }
}
